/**
 * @file client.cc
 * @author HaoyuWang (136046355@qq.com)
 * @brief 测试客户端
 * 编译：g++ -std=c++17 client.cc client_helper.hpp ../proto/login.pb.cc -lpthread -lprotobuf
 * @version 0.1
 * @date 2025-02-12
 * 
 * @copyright Copyright (c) 2025
 * 
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>

#include <iostream>
#include <cstring>
#include <string>
#include <thread>
#include <sstream>

#include "log.h"

#include "send_helper.h"
#include "recv_helper.h"
#include "packet_base.h"


using namespace std;


bool bClose = false;

int Connect(int port, const std::string& addr){
    int clientfd;
    struct sockaddr_in seraddr;
    memset(&seraddr, 0, sizeof(seraddr));

    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(port);
    seraddr.sin_addr.s_addr = inet_addr(addr.c_str());
 
    if (-1==(clientfd = socket(PF_INET, SOCK_STREAM, 0))){
        LOG_ERR("create socket error!");
        return -1;
    }
    
    if (-1 == connect(clientfd, (struct sockaddr*)&seraddr, sizeof(seraddr))){
        LOG_ERR("connect failed!");
        return -1;
    }

    return clientfd;
}

void RecvLoop(int fd, int console_fd){
    RecvHelper recv_helper;
    recv_helper.Init(console_fd, fd);
    while (fd > 0){
        int ret = recv_helper.Recv();
        if(ret < 0){
            ::close(fd);
            fd = -1;
            break;
        }
    }
}

void SendLoop(int fd){
    SendHelper send_helper;
    send_helper.Init();
    send_helper.ListCmds();

    std::string input;
    int val;
    while(fd > 0){
        std::getline(std::cin, input);
        std::stringstream ss(input);
        if(ss >> val && ss.eof()){
            send_helper.Process(val, fd);
        }
    }
}

void MainLoop(){
    int clientfd = Connect(common::SERVER_PORT, common::SERVER_ADDR);
    if(clientfd < 0){
        LOG_ERR("连接服务器失败");
        return;
    }

    int console_fd = Connect(common::CONSOLE_PORT, common::CONSOLE_ADDR);
    if(console_fd < 0){
        LOG_ERR("连接输出控制台失败");
        return;
    }

    thread t(RecvLoop, clientfd, console_fd);
    SendLoop(clientfd);

    t.join();
}

int main(int argc, char const *argv[])
{
    Log::GetInstance().Init();
    MainLoop();
    return 0;
}
